net: add synchronous, role-neutral net.BoundSocket#63951
Conversation
|
Review requested:
|
5db58e1 to
9da4d5f
Compare
9da4d5f to
887d772
Compare
|
I don't understand why this is needed |
There was a problem hiding this comment.
I appreciate this change. net.BoundHandle lets you reserve a TCP port and actually hold onto it until you're ready to use it. This simplifies utility modules like get-port that are susceptible to TOCTOU (Time-of-Check to Time-of-Use) race conditions. Of course, it doesn't solve the problem perfectly since this is in-process only, but I think it's a great improvement.
As a follow-up, it'd be great if BoundHandle could optionally expose its underlying file descriptor, so the reservation can be handed to another process (Unix-only, since this relies on POSIX fd passing). That would extend the same race-free guarantee across a process boundary.
|
Thanks for clarifying the use case here @Ethan-Arrowood. I've gone ahead and added a commit to expose the |
|
@guybedford can you update the docs to clarify when somebody would need this? |
|
is it possible to make this transferable across threads? |
|
@mcollina I've gone ahead and simplified the docs to keep the explanation and example simple. Use cases for binding a In terms of the design, I originally called this For threads, I have already extended the API to support |
5eb9992 to
6007a73
Compare
6007a73 to
6f4089d
Compare
Commit Queue failed- Loading data for nodejs/node/pull/63951 ✔ Done loading data for nodejs/node/pull/63951 ----------------------------------- PR info ------------------------------------ Title net: add synchronous, role-neutral net.BoundSocket (#63951) ⚠ Could not retrieve the email or name of the PR author's from user's GitHub profile! Branch guybedford:tcp-bound-handle -> nodejs:main Labels net, errors, author ready, needs-ci Commits 1 - net: early TCP binding via synchronous net.BoundSocket Committers 1 - Guy Bedford <gbedford@cloudflare.com> PR-URL: https://github.com/nodejs/node/pull/63951 Reviewed-By: Ethan Arrowood <ethan@arrowood.dev> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> ------------------------------ Generated metadata ------------------------------ PR-URL: https://github.com/nodejs/node/pull/63951 Reviewed-By: Ethan Arrowood <ethan@arrowood.dev> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> -------------------------------------------------------------------------------- ℹ This PR was created on Tue, 16 Jun 2026 23:51:31 GMT ✔ Approvals: 3 ✔ - Ethan Arrowood (@Ethan-Arrowood): https://github.com/nodejs/node/pull/63951#pullrequestreview-4516323660 ✔ - James M Snell (@jasnell) (TSC): https://github.com/nodejs/node/pull/63951#pullrequestreview-4535764288 ✔ - Matteo Collina (@mcollina) (TSC): https://github.com/nodejs/node/pull/63951#pullrequestreview-4536589329 ✘ 1 GitHub CI job(s) failed: ✘ - aarch64-linux: with shared boringssl-0.20260526.0: FAILURE (https://github.com/nodejs/node/actions/runs/27852741325/job/82463981053) ℹ Last Full PR CI on 2026-06-20T05:30:24Z: https://ci.nodejs.org/job/node-test-pull-request/74283/ - Querying data for job/node-test-pull-request/74283/ ✔ Build data downloaded ✔ Last Jenkins CI successful -------------------------------------------------------------------------------- ✔ Aborted `git node land` session in /home/runner/work/node/node/.ncuhttps://github.com/nodejs/node/actions/runs/27863741122 |
Signed-off-by: Guy Bedford <guybedford@gmail.com>
6f4089d to
c8d0639
Compare
Signed-off-by: Guy Bedford <guybedford@gmail.com> PR-URL: #63951 Reviewed-By: Ethan Arrowood <ethan@arrowood.dev> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
|
Landed in e3cdb14. |
Signed-off-by: Guy Bedford <guybedford@gmail.com> PR-URL: #63951 Reviewed-By: Ethan Arrowood <ethan@arrowood.dev> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Add net.BoundSocket, a synchronous TCP bind primitive that mirrors POSIX bind(2): the socket is bound to a local address but stays role-agnostic until it is adopted as a server (server.listen()) or a client (new net.Socket({ handle }) followed by connect()).
Constructing a net.BoundSocket binds inline via the existing uv_tcp_bind() path, so the kernel-assigned address (including the ephemeral port when port is 0) is available immediately via boundSocket.address(), and bind errors throw synchronously.
Adoption transfers ownership of the underlying handle; afterwards address() and close() throw ERR_SOCKET_HANDLE_ADOPTED. An un-adopted handle is released with close() or via Symbol.dispose (using).
The handle is passed in-process rather than as a file descriptor, so it also works on Windows.